﻿#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include "pal/protocol/VzClientSDK_LPDefine.h"
#include "pal/protocol/VzClientSDK_CommonDefine.h"
#include "common/socket_tcp.h"
#include "userLog.h"
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>

typedef struct _SOCKET_TCP_SRV_CONTEXT_S
{
	int s32Fd;
	char au8SrvIp[24];
	unsigned short u16SrvPort;
	int s32ListenRunFlag;
	int s32MaxListenNum;
	SocketServerTcpNewConnCb fnNewConnCb;
} SOCKET_TCP_SRV_CONTEXT_S;

static int _CreateServerSocket(void)
{
	int server_s = -1;
	int sock_reused = 1;

	server_s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (server_s == -1)
	{
		perror("socket tcp socket()");
		return -1;
	}

	// set noblock

	// reused
	if ((setsockopt(server_s, SOL_SOCKET, SO_REUSEADDR, (void *)&sock_reused, sizeof(sock_reused))) == -1)
	{
		perror("socket tcp setsockopt()");
		goto _error;
	}

	return server_s;

_error:
	if (sock_reused > 0)
	{
		close(sock_reused);
	}
	return -1;
}

static int _BindServer(int s32ServerSock, char *ps8ServerIp, unsigned short u16Port)
{

	struct sockaddr_in server_sockaddr;

	memset(&server_sockaddr, 0, sizeof server_sockaddr);
	server_sockaddr.sin_family = AF_INET;
	if (ps8ServerIp != NULL)
	{
		inet_aton(ps8ServerIp, &server_sockaddr.sin_addr);
	}
	else
	{
		server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	}
	server_sockaddr.sin_port = htons(u16Port);

	if (bind(s32ServerSock, (struct sockaddr *)&server_sockaddr, sizeof(server_sockaddr)) < 0)
	{
		perror("socket tcp bind");
		return -1;
	}

	return 0;
}

static int _ListenThread(SOCKET_TCP_SRV_CONTEXT_S *pstCtx)
{
	int s32Ret = 0;
	struct sockaddr *addr;
	struct sockaddr_in stAddr_in;
	socklen_t s32Len = sizeof(struct sockaddr_in);
	SOCKET_CONNECT_S stNewConn;

	s32Ret = listen(pstCtx->s32Fd, pstCtx->s32MaxListenNum);
	if (s32Ret == -1)
	{
		perror("socket tcp server");
		return -1;
	}

	while (pstCtx->s32ListenRunFlag)
	{
		memset(&stAddr_in, 0, sizeof(stAddr_in));
		memset(&stNewConn, 0, sizeof(stNewConn));
		s32Ret = accept(pstCtx->s32Fd, (struct sockaddr *)&stAddr_in, &s32Len);
		if (s32Ret < 0)
		{
			perror("socket server tcp accept");
			if (errno == EINTR)
			{
				usleep(100 * 1000);
				continue;
			}
			printf("###############socket tcp accept() error\n");
			return -1;
		}
		else
		{
			stNewConn.s32Fd = s32Ret;
			strcpy(stNewConn.as8RemoteIp, inet_ntoa(stAddr_in.sin_addr));
			stNewConn.s32RemotePort = ntohs(stAddr_in.sin_port);
			if (pstCtx->fnNewConnCb)
			{
				pstCtx->fnNewConnCb(stNewConn);
			}
		}
	}

	return 0;
}

SOCKET_SRV_TCP_HANDLE SocketTcpServerCreate(char *ps8Ip, unsigned short u16Port, int s32MaxConn, SocketServerTcpNewConnCb fnNewConnCb)
{
	int s32ServerSock = 0;
	pthread_t stListenThread, stAcceptThread;
	int s32Ret = 0;
	SOCKET_TCP_SRV_CONTEXT_S *pstCtx;
	int s32SocketFd = -1;

	pstCtx = (SOCKET_TCP_SRV_CONTEXT_S *)malloc(sizeof(SOCKET_TCP_SRV_CONTEXT_S));
	if (pstCtx == NULL)
	{
		printf("malloc for socket server tcp error\n");
		return NULL;
	}

	memset(pstCtx, 0, sizeof(SOCKET_TCP_SRV_CONTEXT_S));
	if (ps8Ip)
	{
		strcpy(pstCtx->au8SrvIp, ps8Ip);
	}
	else
	{
		strcpy(pstCtx->au8SrvIp, "0.0.0.0");
	}
	pstCtx->u16SrvPort = u16Port;
	pstCtx->fnNewConnCb = fnNewConnCb;
	pstCtx->s32MaxListenNum = s32MaxConn;
	pstCtx->s32ListenRunFlag = 1;

	// 申请socket
	s32SocketFd = _CreateServerSocket();
	if (s32SocketFd < 0)
	{
		printf("_CreateServerSocket error\n");
		goto _error;
	}

	printf("################################get server socket:%d\n", s32SocketFd);

	pstCtx->s32Fd = s32SocketFd;

	// bind
	if (_BindServer(pstCtx->s32Fd, ps8Ip, pstCtx->u16SrvPort) < 0)
	{
		printf("_BindServer error\n");
		goto _error;
	}

	// create listen and accept task
	s32Ret = pthread_create(&stListenThread, NULL, _ListenThread, (void *)pstCtx);
	if (s32Ret == -1)
	{
		perror("_ListenThread");
		goto _error;
	}

	usleep(200 * 1000);

	return (SOCKET_SRV_TCP_HANDLE)pstCtx;

_error:
	if (s32SocketFd > 0)
	{
		close(s32SocketFd);
	}
	if (pstCtx)
	{
		free(pstCtx);
	}
	return NULL;
}

int SocketTcpServerDestroy(SOCKET_SRV_TCP_HANDLE hHandle)
{
	SOCKET_TCP_SRV_CONTEXT_S *pstCtx = (SOCKET_TCP_SRV_CONTEXT_S *)hHandle;

	if (pstCtx)
	{
		if (pstCtx->s32Fd > 0)
		{
			close(pstCtx->s32Fd);
		}
		free(pstCtx);
	}

	return 0;
}

int SocketTcpClientCreate(char *ps8ServerIp, int s32ServerPort, unsigned char timeOut)
{
	int sock = -1;
	struct sockaddr_in server_addr;
	socklen_t sockaddr_len = 0;

	struct timeval tvOut;
	tvOut.tv_sec = timeOut;
	tvOut.tv_usec = 0;

	sock = socket(AF_INET, SOCK_STREAM, 0);
	if (sock < 0)
	{
		LOG_ERROR("socket（%s:%d） 创建失败: %s", ps8ServerIp, s32ServerPort, strerror(errno));
		return -1;
	}
	if (timeOut > 0)
	{
		setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tvOut, sizeof(tvOut));
		setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tvOut, sizeof(tvOut));
	}
	bzero(&server_addr, sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(s32ServerPort);
	inet_aton(ps8ServerIp, &server_addr.sin_addr);
	sockaddr_len = sizeof(server_addr);
	if (connect(sock, (struct sockaddr *)&server_addr, sockaddr_len) == -1)
	{
		LOG_ERROR("socket（%s:%d） 连接失败: %s", ps8ServerIp, s32ServerPort, strerror(errno));
		close(sock);
		return -1;
	}

	return sock;
}

int SocketTcpClientDestroy(int s32SocketFd)
{
	if (s32SocketFd > 0)
	{
		shutdown(s32SocketFd, SHUT_RDWR);
		close(s32SocketFd);
	}
	return 0;
}

int __SocketTcpSend(int s32SocketFd, char *ps8Buf, int s32Len, int s32Timeout)
{
#if 1
	int nRet = 0;
	int nRemainSize = s32Len;
	int nOffset = 0;

	while (nRemainSize > 0)
	{
		nRet = send(s32SocketFd, ps8Buf + nOffset, s32Len - nOffset, 0);
		if (nRet < 1)
		{
			if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)
			{
				//				printf("SocketTcpSend send EINTR,EWOULDBLOCK,EAGAIN\n");
				usleep(5 * 1000);
				continue;
			}
			else
			{

				return nRet;
			}
		}

		nRemainSize -= nRet;
		nOffset += nRet;
	};

	return s32Len;
#else
	return send(s32SocketFd, ps8Buf, s32Len, 0);
#endif
}
#define TCP_MTU_MAX 1200
int SocketTcpSend(int s32SocketFd, char *ps8Buf, int s32Len, int s32Timeout)
{
	int nRemainSize = s32Len;
	unsigned int dwDataSend = 0;
	unsigned int dwOffset = 0;
	int nRet = 0;
	while (nRemainSize > 0)
	{
		if (nRemainSize > TCP_MTU_MAX)
		{
			dwDataSend = TCP_MTU_MAX;
		}
		else
		{
			dwDataSend = nRemainSize;
		}
		nRet = __SocketTcpSend(s32SocketFd, ps8Buf + dwOffset, dwDataSend, s32Timeout);
		if (nRet < 1)
		{
			return nRet;
		}
		dwOffset += nRet;
		nRemainSize -= nRet;
	}
	return s32Len;
}

/*返回0表示EINTR，EWOULDBLOCK，EAGAIN，返回<0表示出错，返回>0成功*/
int SocketTcpRecvSync(int s32SocketFd, char *ps8Buf, int s32Len)
{
	int nRet = 0;

	nRet = recv(s32SocketFd, ps8Buf, s32Len, 0);
	if (nRet < 1)
	{
		if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)
		{
			printf("错误代码errno：%d\n", errno);
			return 0;
		}
		else
		{
			return -1;
		}
	}

	return nRet;
}

/*返回0表示EINTR，EWOULDBLOCK，EAGAIN，返回<-1表示出错，返回-2表示超时，返回>0成功*/
int SocketTcpRecvSelect(int s32SocketFd, char *ps8Buf, int s32Len, int s32Timeout)
{
	int nRet = 0;
	fd_set stReadFds;
	struct timeval tv;

	if (s32SocketFd < 0)
	{
		return -1;
	}

	/*select 等待延时*/
	tv.tv_sec = s32Timeout / 1000;
	tv.tv_usec = (s32Timeout % 1000) * 1000;

	FD_ZERO(&stReadFds);
	FD_SET(s32SocketFd, &stReadFds);
	nRet = select(s32SocketFd + 1, &stReadFds, NULL, NULL, &tv);
	if (nRet > 0)
	{
		if (FD_ISSET(s32SocketFd, &stReadFds))
		{
			nRet = recv(s32SocketFd, ps8Buf, s32Len, 0);
			if (nRet < 1)
			{
				if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)
				{
					//					printf("SocketTcpRecvSync recv EINTR,EWOULDBLOCK,EAGAIN\n");
					return 0;
				}
				else
				{
					printf("fun=%s line=%d nRet=%d\n", __FUNCTION__, __LINE__, nRet);
					perror(" 1error");
					return -1;
				}
			}
			return nRet;
		}
		return -2;
	}
	else if (nRet == 0)
	{
		return -2;
	}
	else
	{
		perror(" 2error");
		return -1;
	}
	perror(" 3error");
	return -1;
}

int SocketTcpOptSetBufSize(int s32SocketFd, SOCKET_SET_BUF_SIZE_E eType, int s32Size)
{
	int nMaxBuf = 0;
	int nType = 0;

	if (s32Size <= 0)
	{
		return -1;
	}

	if (eType == SOCKET_SET_BUF_SIZE_SEND)
	{
		nType = SO_SNDBUF;
	}
	else if (eType == SOCKET_SET_BUF_SIZE_RECV)
	{
		nType = SO_RCVBUF;
	}
	else
	{
		printf("unknow set buf type:%d\n", eType);
		return -1;
	}

	nMaxBuf = s32Size;
	if (setsockopt(s32SocketFd, SOL_SOCKET, nType, (char *)&nMaxBuf, sizeof(nMaxBuf)) == -1)
	{
		printf("SocketTcpSetSendBufSize() error !!!!!!\n");
		return -1;
	}
	return 0;
}
